/**
 ****************************************************************************
 * Copyright (C) Marcelo F. Ochoa. All rights reserved.                      *
 * ------------------------------------------------------------------------- *
 * This software is published under the terms of the Apache Software License *
 * version 1.1, a copy of which has been included  with this distribution in *
 * the LICENSE file.                                                         *
 */

package com.prism;

import java.util.Enumeration;
import java.util.Hashtable;
import java.util.StringTokenizer;

import org.jconfig.Configuration;

/**
 * This class implements a Dictionary for transaction Definitions.
 * Using the Resource Manager, you associate URIs with the operations on
 * transactions (begin, commit, and rollback). When a user invokes one of these URIs,
 * the corresponding transaction operation is performed by the ResourceManager.
 * These URIs can be mapped to stored procedures that display appropriate pages to the user. For example, the begin
 * transaction URI could display to the user a list of items to add to his or her shopping cart, the
 * commit transaction URI could display to the user a list of purchased items, and
 * the rollback transaction URI could display to the user a page that asks if he wants
 * to drop the existing shopping cart and start another one.
 * Between the begin and the commit or rollback URI, the user invokes other URIs that
 * call procedures to perform some action on the database. These procedures might or
 * might not belong to a transaction. If the URI belongs to a transaction, the actions
 * performed by that procedure would be committed or rolled back when the transaction
 * ends. If the URI does not belong to the transaction, it is not affected by the transaction,
 * and Prism treats it as a regular request (changes made by that URI are committed upon completion).
 * URIs belonging to a transaction usually invoke procedures within a package.
 * The sequence of URIs for a stored procedures within the database when invoked would look like follows:<BR><UL>
 * <LI>begin a transaction http://host:port/servlet/demo/test.txn_begin</LI>
 * <LI>the first operation in the transaction http://host:port/servlet/demo/test.txn_update1</LI> 
 * <LI>the second operation in the transaction http://host:port/servlet/demo/test.txn_update2</LI> 
 * <LI>some more operations</LI> 
 * <LI>commit the transaction http://host:port/servlet/demo/test.txn_commit</LI></UL><BR>
 * See prism.xconf to get the exact sintax of definition<BR> 
 * <BR>
 * Modified: 4/Nov/2003 by <a href="mailto:pyropunk@usa.net">Alexander Graesser</a> (LXG)<BR>
 * Changes : <UL><LI>Added log4j logging</LI>
 *           <LI>JavDoc cleanup</LI>
 *           <LI>code cleanup</LI></UL>
 */
public class TxDicc {
    private static TxDicc instance = null;
    private static Configuration properties = null;
    public static Hashtable dicc;
    public java.lang.String BeginURI;
    public java.lang.String CommitURI;
    public java.lang.String RollBackURI;
    public java.lang.String[] BelongTo;
    public int timeOut = 0;
    public java.lang.String txName;
    public int lastComp;
    public static final int UNDF = 0;
    public static final int BGN = 1;
    public static final int CMMT = 2;
    public static final int ROLL = 3;
    public static final int BLNG = 4;

    public static void init(Configuration props) {
        //System.out.println("Initializing Transaction manager Dicc...");
        String txnames = props.getProperty("TxNames","","Manager");
        if (instance == null) {
            instance = new TxDicc();
            dicc = new Hashtable();
            properties = props;
            StringTokenizer st = new StringTokenizer(txnames, " ");
            while (st.hasMoreElements()) {
                String txdef = (String)st.nextElement();
                //System.out.println("\nAdd transaction "+txdef+" definition...");
                dicc.put(txdef, new TxDicc(txdef));
            }
        }
    }

    public static void release() {
        //System.out.println("Cleanup Transaction manager Dicc...");
        if (instance != null) {
          properties = null;
          dicc.clear();
          dicc = null;
          instance = null;
        }
    }
    
    public TxDicc() { 
      // LXG: call to super is generated anyway but put it here for clarity.
      super();
    }

    public TxDicc(String txdef) {
        int blngto = 0;
        txName = txdef;
        BeginURI = properties.getProperty("BeginURI",null,"TX_"+txdef);
        CommitURI = properties.getProperty("CommitURI",null,"TX_"+txdef);
        RollBackURI = properties.getProperty("RollBackURI",null,"TX_"+txdef);
        timeOut = properties.getIntProperty("TimeOut",500,"TX_"+txdef);
        //System.out.println("Add BeginURI ="+BeginURI+" definition...");
        //System.out.println("Add CommitURI ="+CommitURI+" definition...");
        //System.out.println("Add RollBackURI ="+RollBackURI+" definition...");
        //System.out.println("Add timeout ="+timeOut+" definition...");
        StringTokenizer st = new StringTokenizer(properties.getProperty("BelongTo","","TX_"+txdef), ";");
        while (st.hasMoreElements()) {
            blngto++;
            st.nextElement();
        }
        st = new StringTokenizer(properties.getProperty("BelongTo","","TX_"+txdef), ";");
        BelongTo = new String[blngto];
        for (int i = 0; st.hasMoreElements(); i++) {
            String s = (String)st.nextElement();
            BelongTo[i] = s.substring(0, s.indexOf("*"));
            //System.out.println("Add BelongTo ="+BelongTo[i]+" definition...");
        }
    }

    public static Enumeration getAll() {
        return dicc.elements();
    }

    public int getType(String URI) {
        if (URI.startsWith(BeginURI))
            return BGN;
        else if (URI.startsWith(CommitURI))
            return CMMT;
        else if (URI.startsWith(RollBackURI))
            return ROLL;
        else
            for (int i = 0; i < BelongTo.length; i++) {
                if (URI.startsWith(BelongTo[i]))
                    return BLNG;
            }
        return UNDF;
    }

    public static TxDicc getTxDef(String URI) {
        Enumeration e = dicc.elements();
        while (e.hasMoreElements()) {
            TxDicc tx = (TxDicc)e.nextElement();
            if ((tx.lastComp = tx.getType(URI)) != UNDF)
                return tx;
        }
        return null;
    }

    public static String getTxName(String URI) {
        Enumeration e = dicc.elements();
        while (e.hasMoreElements()) {
            TxDicc tx = (TxDicc)e.nextElement();
            if ((tx.lastComp = tx.getType(URI)) != UNDF)
                return tx.txName;
        }
        return null;
    }
}
